home *** CD-ROM | disk | FTP | other *** search
- /*
- * R M A I L . C
- *
- * Developed from the Berkeley mail program of the same name
- * by Mike Obrien at RAND to run with the MMDF mail system.
- * Rewritten by Doug Kingston, US Army Ballistics Research Laboratory
- * Hacked a lot by Steve Bellovin (smb@unc)
- *
- * This program runs SETUID to Opr so that it can set effective and
- * real [ug]ids to mmdflogin.
- *
- * Steve Kille - Aug 84
- * Take machete to it. Use protocol mode,
- * and always go thru submit - phew
- * Lee McLoughlin Oct 84.
- * Address munges some header lines into 822 format.
- * Peter Collinson Dec 85.
- * Lee's version was dependent on
- * (a) the uucp channel
- * (b) the domain tables associated with the uucp channel
- * This version costs more cycles (but there is generally
- * only one of these running on a machine at a time) and
- * uses mmdf's tables to dis-assemble bang routes converting
- * them into a domain address.
- * Peter Collinson March 87.
- * Add the CITATION ifdef to allow shortened messages to be
- * returned on failure. The value of CITATION is the number of
- * message lines returned. Change the format of bounced messages
- * to be more like the rest of MMDF. Add a line formatter so that
- * error messages are folded over several lines.
- * Add sundry (void)'s to stop the C compiler on the HLH Orion
- * complaining.
- * Peter Collinson June 87
- * The existing version send bang addresses into submit
- * from the rmail command line. This breaks other channels
- * which do not know about !'s. So, alter any PURE bang
- * address into a 733 % % % @ sequence allowing the uucp
- * channel to change these back to ! ! ! and other channels
- * to deal with them appropriately.
- *
- * Jacob Gore May 89
- * Instead of converting "a!b!c!user" to "user%c%b@a", which
- * does NOT get converted back by the uucp channel, just convert
- * it to pseudo-RFC-976 form, "b!c!user@a" ("pseudo-" because
- * "a" by itself may not be a valid internet hostname).
- */
- #undef RUNALON
-
- #include "util.h"
- #include "mmdf.h"
- #include "ap.h"
- #include "ch.h"
- #include "dm.h" /* needed for host_equal */
- #include <pwd.h>
- #include <signal.h>
- #include <sys/stat.h>
-
- #define VERSION "4.0"
-
- #define CITATION 6 /* Added Peter C March 1987 */
- /* when bouncing only bounce part of */
- /* a message */
-
- #define NAMESZ 256 /* Limit on component name size. LMCL was 64 */
- #define MAXADRS 6 /* Max no. of adrs to output on a single line */
- #define MAXERRSTASH 5
- #define ungetline(s) ((void) strcpy(tmpline,s),usetmp=1)
-
- typedef struct {
- char *hname;
- int hfound;
- } Hdrselect;
-
- typedef struct { /* Where to save returnerror messages */
- char e_s_dest[LINESIZE];
- struct rp_bufstruct e_s_reason;
- } Err_stash;
-
- typedef struct {
- char *o_host; /* Host name */
- char *o_official; /* Official name */
- } Official;
-
- Hdrselect hdrselect[] = {
- #define HDATE 0
- "date", 0, /* this is a little naughty - we need */
- /* to register that we have had this */
- /* but not address munge it */
- /* so it has token 0 */
- #define HFROM 1
- "from", 0,
- #define HTO 2
- "to", 0,
- #define HCC 3
- "cc", 0,
- #define HBCC 4
- "bcc", 0,
- #define HSENDER 5
- "sender", 0,
- #define HREPLY 6
- "reply-to", 0,
- #define HRFROM 7
- "resent-from", 0,
- #define HRSENDER 8
- "resent-sender",0,
- #define HRTO 9
- "resent-to", 0,
- 0, 0
- };
-
- Err_stash e_stash[MAXERRSTASH];
-
- extern LLog *logptr;
- extern char *locfullname;
- extern char *Uchan;
- extern char *mmdflogin;
- extern char *sitesignature;
- extern char *supportaddr;
- extern char *optarg;
-
- extern char *index();
- extern char *rindex();
- extern char *getenv(); /* get the Accounting system from the environment */
- extern char *strdup();
- extern char *malloc();
- extern char *compress();
-
- extern int optind;
-
- FILE *rm_msgf; /* temporary out for message text */
- Chan *chanptr;
- char Msgtmp[] = "/tmp/rmail.XXXXXX";
- char *next = NULL; /* Where nextchar() gets the next char from */
- char rm_date[LINESIZE]; /* date of origination from uucp header */
- char rm_from[LINESIZE]; /* accumulated path of sender */
- char origsys[NAMESZ]; /* originating system */
- char origpath[LINESIZE]; /* path from us to originating system */
- char Mailsys[LINESIZE]; /* Mail system signature */
- char tmpline[LINESIZE]; /* Temp buffer for continuations and such */
- char adrs[LINESIZE]; /* Partly munged addresses go here */
- char linebuf[LINESIZE]; /* scratchpad */
- char nextdoor[LINESIZE]; /* The site nextdoor who sent the mail */
- char uchan[LINESIZE]; /* Channel to use for submission */
-
- int Tmpmode = 0600;
- int usetmp = 0; /* whether tmpline should be used */
- int e_s_count;
- int e_s_other;
- int debug;
-
-
- main(argc, argv)
- char **argv;
- {
- struct passwd *pw, *getpwnam(), *getpwuid();
- char *fromptr, *cp, *d;
- char fromwhom[NAMESZ]; /* user on remote system */
- char sys[NAMESZ]; /* an element in the uucp path */
- int fd;
-
- mmdf_init(argv[0]);
-
- while ((fd = getopt(argc, argv, "df:")) != EOF) {
- switch (fd) {
- case 'd':
- debug = 1;
- break;
-
- case 'f':
- close(0);
- open(optarg, 0);
- break;
- }
- }
-
- if (optind == argc) {
- fprintf(stderr, "Usage: rmail user [user ...]\n");
- exit(1);
- }
-
- #if 0
- /*
- * point standard error and standard out at /dev/null
- */
- if (debug == 0) {
- close(1);
- open("/dev/null", 1);
- close(2);
- dup(1);
- }
- #endif
-
- umask(0);
-
- /*
- * First, change effective and real UID/GID into Mailsys owner
- */
- if ((pw = getpwnam(mmdflogin)) == NULL) {
- fprintf(stderr, "Cannot find mmdflogin\n");
- exit(99);
- }
- setgid(pw->pw_gid);
- setuid(pw->pw_uid);
-
- (void) sprintf(Mailsys, "%s <%s@%s>",
- sitesignature, mmdflogin, locfullname);
-
- /*
- * Create temp file for body of message
- */
- mktemp(Msgtmp);
- if ((fd = creat(Msgtmp, Tmpmode)) < 0)
- bomb("Can't create %s\n", Msgtmp);
- close(fd);
-
- if ((rm_msgf = fopen(Msgtmp, "r+")) == NULL)
- bomb("Can't reopen %s\n", Msgtmp);
-
- unlink(Msgtmp);
-
- /*
- * Unravel the From and >From lines at the head of the message
- * to work who sent it, the path it took to get here and when
- * it was sent.
- *
- * Some or all of this info may be ignore depending on the 822 header
- * info given.
- */
- for (;;) {
- if (gets(linebuf) == NULL)
- break;
- if (strncmp(linebuf, "From ", 5) &&
- strncmp(linebuf, ">From ", 6))
- break;
-
- cp = index(linebuf, ' '); /* start of name */
- fromptr = ++cp;
- cp = index(cp, ' '); /* cp at end of name */
- *cp++ = '\0'; /* term. name, cp at date */
- (void) strcpy(fromwhom, fromptr);
- while (isspace(*cp)) cp++; /* Skip any ws */
- /*
- * The date is the rest of the line ending at \0 or remote
- */
- d = rm_date;
- while (*cp && strncmp(cp, " remote from ", 13))
- *d++ = *cp++;
- *d = '\0';
-
- for (;;) {
- cp = index(cp+1, 'r');
- if (cp == NULL) {
- cp = rindex(fromwhom, '!');
- if (cp != NULL) {
- char *p;
- *cp = '\0';
- p = rindex(fromwhom, '!');
- if (p != NULL)
- (void) strcpy(origsys, p+1);
- else
- (void) strcpy(origsys, fromwhom);
- (void) strcat(rm_from, fromwhom);
- (void) strcat(rm_from, "!");
- (void) strcpy(fromwhom, cp+1);
- goto out;
- }
- /*
- * Nothing coherent found - so look in
- * environment for ACCTSYS
- */
- if ((cp = getenv("ACCTSYS")) && *cp) {
- (void) strcpy(origsys, cp);
- (void) strcat(rm_from, cp);
- (void) strcat(rm_from, "!");
- goto out;
- }
- cp = "remote from somewhere";
- }
- if (strncmp(cp, "remote from ", 12) == 0)
- break;
- }
-
- sscanf(cp, "remote from %s", sys);
- (void) strcat(rm_from, sys);
- (void) strcpy(origsys, sys); /* Save for quick ref. */
- (void) strcat(rm_from, "!");
- }
- out:
- if (fromwhom[0] == '\0') /* No from line, illegal */
- bomb("No from lines in message\n");
-
- ungetline(linebuf);
-
- /*
- * Complete the from field
- */
- (void) strcat(rm_from, fromwhom);
-
- /*
- * A uk special - see if the first two components of the constructed
- * bang address are in fact the same site. If so replace by their
- * official name
- */
- domain_cross(rm_from);
-
- /*
- * Save a copy of the path to the original site.
- * This is all the the path we were given - the user name after
- * the last !. NOTE: We keep the trailing !, hence the +1.
- */
- (void) strcpy(origpath, rm_from);
- *(rindex(origpath, '!') + 1) = '\0';
-
- /*
- * Savepath is given a copy of the immediate neighbour
- */
- if ((d = index(rm_from, '!')) != NULL) {
- *d = '\0';
- (void) strcpy(nextdoor, rm_from);
- *d = '!';
- }
- else
- (void) strcpy(nextdoor, rm_from);
-
- /*
- * Find the channel depending in the nextdoor site
- */
- set_channel(nextdoor);
- ch_llinit(chanptr);
-
- /*
- * Convert the from to Arpa format and leave it in from
- */
- fromcvt(rm_from, fromwhom);
- (void) strcpy(rm_from, fromwhom);
-
- if (debug)
- printf("from=%s, origpath=%s, date=%s\n",
- rm_from, origpath, rm_date);
-
- msgfix(rm_from, rm_date);
-
- xsubmit(rm_from, argv, argc);
-
- exit(0);
- }
-
- /*
- * Munge the message header.
- *
- * All header lines with addresses in are munged into 822 format.
- * If no "From:" line is given supply one based on the UUCP Froms, do the
- * same if no "Date:".
- */
- /*
- * Is this header in the list of those to have their addresses munged?
- * returnheader value offset value
- * notice that it returns 0 for the date header
- */
- shouldmunge(name)
- char *name;
- {
- register Hdrselect *h;
-
- if (debug)
- printf("in shouldmunge with '%s'\n", name);
-
- for (h = hdrselect; h->hname != NULL; h++)
- if (lexequ(h->hname, name)) {
- h->hfound++;
- return(h - hdrselect);
- }
-
- return(0);
- }
-
- /*
- * If this is a header line then grab the name of the header and stuff it
- * into 'name' then return a pointer to the actually body of the line.
- * Otherwise return NULL.
- *
- * NOTE: A header is a line that begins with a word formed of alphanums and
- * dashes (-) then possibly some whitespace then a colon (:).
- */
- char *
- grabheader(s, name)
- register char *s, *name;
- {
- char tmpbuf[LINESIZE];
-
- /*
- * Copy the name into name
- */
- while (isalpha(*s) || isdigit(*s) || *s == '-')
- *name++ = *s++;
- *name = '\0';
-
- /*
- * Skip any whitespace
- */
- while (isspace(*s))
- s++;
-
- /*
- * This is a header if the next char is colon
- */
- if (*s == ':') {
- s++;
- /*
- * This is probably illegal but we fail horribly if it
- * happens - so we will guard against it
- */
- if (*s != ' ' && *s != '\t' && *s != '\0') {
- /* we need to add a space */
- (void) strcpy(tmpbuf, s);
- (void) sprintf(s, " %s", tmpbuf);
- }
- return(s); /* Return a pointer to the rest of the line */
- }
-
- return(NULL);
- }
-
- msgfix(from, date)
- char *from, *date;
- {
- register char *s;
- register int c;
- char *rest, *lkp;
- char name[LINESIZE], tmpbuf[LINESIZE];
- char *grabline();
- int haveheader = 0; /* Do I have a header? */
- int headertoken;
-
- /*
- * Loop through all the headers
- */
- while (1) {
-
- if (debug)
- printf("in msgfix about to grabline\n");
-
- s = grabline();
-
- if (debug)
- printf("got '%s'\n", s);
-
- /*
- * Is this the end of the header?
- */
- if (*s == '\0' || feof(stdin))
- break;
-
-
- /*
- * Is this a continuation line?
- */
- if (haveheader && isspace(*s)) {
- /* Note: Address munged headers handled specially */
- fprintf(rm_msgf, "%s\n", s);
- }
- else {
- /*
- * Grab the header name from the line
- */
- if ((rest = grabheader(s, name)) == NULL)
- /* Not a header therefore all headers done */
- break;
-
- haveheader = 1;
-
- /*
- * Should I address munge this?
- */
- if (headertoken = shouldmunge(name)) {
- char *finalstr;
- finalstr = "\n";
- fprintf(rm_msgf, "%s: ", name);
- /*
- * deal specially with From lines
- * the parser loses comments so we retain
- * them specially here
- */
- if (headertoken == HFROM
- || headertoken == HRFROM) {
- if (lkp = index(rest, '<')) {
- *lkp = '\0';
- if (*rest == ' ')
- fprintf(rm_msgf, "%s<", rest+1);
- else
- fprintf(rm_msgf, "%s<", rest);
- *lkp = '<';
- finalstr = ">\n";
- (void) strcpy(tmpbuf, lkp);
- /*
- * notice that we copy from the
- * '<' to start with a space
- */
- tmpbuf[0] = ' ';
- rest = tmpbuf;
- lkp = rindex(rest, '>');
- if (lkp)
- *lkp = '\0';
- }
- if (lkp = index(rest, '(')) {
- *lkp = '\0';
- (void) sprintf(tmpbuf, " (%s\n", lkp+1);
- finalstr = tmpbuf;
- }
- }
- hadr_munge(rest);
- fputs(finalstr, rm_msgf);
- }
- else
- fprintf(rm_msgf, "%s\n", s);
- }
- }
-
- /*
- * No From: line was given, create one based on the From's
- */
- if (hdrselect[HFROM].hfound == 0) {
- fprintf(rm_msgf, "From: %s\n", from);
- }
-
- /*
- * No Date: line was given, create one based on the From's
- */
- if (hdrselect[HDATE].hfound == 0) {
- datecvt(date, tmpbuf); /* Convert from uucp -> Arpa */
- fprintf(rm_msgf, "Date: %s\n", tmpbuf);
- }
-
- /*
- * Copy the rest of the file, if there is any more
- */
- if (!feof(stdin)) {
- /*
- * If the first line of the message isn't blank
- * output the blank separator line.
- */
- if (*s)
- putc('\n', rm_msgf);
- fprintf(rm_msgf, "%s\n", s);
- while ((c = getchar()) != EOF) {
- if (ferror(stdin))
- fputs("\n *** Problem during receipt from UUCP ***\n", rm_msgf);
- putc(c, rm_msgf);
- }
- }
- }
-
- char *
- grabline()
- {
- if (debug)
- printf("in grabline ");
-
- /*
- * Grab the next line.
- * Remembering this might be the tmpline
- */
- if (usetmp) {
- if (debug)
- printf("using tmpline ");
- (void) strcpy(linebuf, tmpline);
- usetmp = 0;
- }
- else
- gets(linebuf);
-
- /* Anything wrong? */
- if (ferror(stdin))
- fputs("\n *** Problem during receipt from UUCP ***\n", rm_msgf);
-
- if (debug)
- printf("returning '%s'\n ", linebuf);
-
- return(linebuf);
-
- }
-
- nextchar()
- {
- register char *s; /* scratch pointer. */
-
- if (next != NULL && *next != '\0') {
- if (debug)
- printf("<%c>", *next);
- return(*next++);
- }
-
- /*
- * The last buffer is now empty, fill 'er up
- */
- next = grabline();
-
- if (feof(stdin) || !isspace(*next) || *next == '\0') {
- /* Yipee! We've reached the end of the address list. */
- ungetline(next);
- next = NULL; /* Force it to read buffer */
- return(-1);
- }
-
- /* Zap excess whitespace */
- (void) compress(next, adrs);
-
- /*
- * This may be a slightly duff list generated by some of the
- * UNIX mailers eg: "x y z" rather than "x,y,z"
- * If it is in this ^^^^^^^ convert to ^^^^^^^
- * NOTE: This won't handle list: "x<x@y> y<y@z>" conversions!
- */
- if (index(adrs, ' ') != NULL &&
- index(adrs, ',') == NULL &&
- index(adrs, '<') == NULL &&
- index(adrs, '(') == NULL &&
- index(adrs, '"') == NULL) {
- for (s = adrs; *s; s++)
- if (*s == ' ')
- *s = ',';
- }
- next = adrs;
- /* This is a continuation line so return a seperator just in case */
- return(',');
- }
-
- /*
- * Munge an address list thats part of a header line. Try and get the
- * ap_* (MMDF) routines to do as much as possible for us.
- */
- hadr_munge(list)
- char *list;
- {
- AP_ptr the_addr; /* ---> THE ADDRESS <--- */
- int adrsout = 0; /* How many address have been output */
-
- ungetline(list);
-
- while (1) {
- AP_ptr ap_pinit();
-
- the_addr = ap_pinit(nextchar);
-
- if (the_addr == (AP_ptr)NOTOK)
- bomb("cannot initialise address parser!");
-
- ap_clear();
-
- switch(ap_1adr()) {
- case NOTOK:
- /* Something went wrong!! */
- (void) ap_sqdelete(the_addr, (AP_ptr)NULL);
- ap_free(the_addr);
- /*
- * Emergency action in case of parser break down:
- * print out the rest of the line (I hope).
- */
- fprintf(rm_msgf, "%s", tmpline);
- continue;
-
- case OK:
- /*
- * I've got an address to output!
- * Output a comma seperator between the addresses
- * and a newline every once in a while to make
- * sure the lines aren't too long
- */
- if (adrsout++)
- fprintf(rm_msgf, ",%s ", adrsout%MAXADRS?"":"\n");
-
- /* Munge will do all the work to output it */
- munge(the_addr);
-
- /* Reclaim the space */
- (void) ap_sqdelete(the_addr, (AP_ptr)NULL);
- ap_free(the_addr);
-
- if (debug)
- printf("munged and space freed\n");
- break;
-
- case DONE:
- if (debug)
- printf("hadr_munge all done\n");
-
- /* Reclaim the space */
- (void) ap_sqdelete(the_addr, (AP_ptr)NULL);
- ap_free(the_addr);
-
- return;
- }
- }
- }
-
- /*
- * We now have a single address in the_addr to output.
- */
- munge(the_addr)
- AP_ptr the_addr;
- {
- AP_ptr local, domain, route;
- char *s, *frees;
- char adr[LINESIZE];
- char *ap_p2s();
-
- if (debug)
- printf("in munge with: ");
-
- /*
- * Find where the important bits begin in the tree
- */
- (void) ap_t2parts(the_addr, (AP_ptr *)NULL, (AP_ptr *)NULL,
- &local, &domain, &route);
-
- /*
- * Convert from the tree back into a string
- */
- frees = s = ap_p2s((AP_ptr)NULL, (AP_ptr)NULL, local, domain, route);
-
- if (debug)
- printf("%s\n", s);
-
- /* Is it a uucp style address? */
- if (domain == (AP_ptr) 0 && index (s, '!') != (char *)NULL) {
- char adr2[LINESIZE];
-
- (void) strcpy(adr, s);
-
- /*
- * Stick the path it took to get here at the start.
- * But try to avoid any duplicates by overlapping
- * the matching parts of the address. Eg:
- * adr = 'x!y!z' path = 'a!b!x!y!'
- * adr2 = 'a!b!x!y!z'
- */
- for (s = origpath; *s; s++) {
- /* Does it match? */
- if (strncmp(adr, s, strlen(s)) == 0) {
- char c = *s;
- *s = '\0';
- (void) strcpy(adr2, origpath);
- (void) strcat(adr2, adr);
- *s = c;
- break;
- }
- }
-
- /*
- * Did I just scan the whole path without finding a match!
- */
- if (*s == '\0') {
- /* Append the adr to the path */
- (void) strcpy(adr2, origpath);
- (void) strcat(adr2, adr);
- }
-
- /* Munge the address into its shortest form and print it */
- fromcvt(adr2, adr);
- fprintf(rm_msgf, "%s", adr);
-
- if (debug)
- printf("uucp munge gives %s\n", adr);
- }
- else {
- extern int ap_outtype;
- AP_ptr norm;
- char *at, *brace, *fmt, *official, *p;
- char *get_official();
-
- /*
- * Normalise the address
- */
- ap_outtype = AP_733; /* Hmm. Maybe should be from channel */
- norm = ap_normalize(nextdoor, (char *)NULL, the_addr, chanptr);
-
- /* Convert it back in to a string and output it */
- (void) ap_t2s(norm, &p);
- if (debug)
- printf("Normalised address: %s\n", p);
- /*
- * Look for the last address component and re-write to the
- * official form. There are probably better ways of doing this
- */
- at = rindex(p, '@');
- fmt = "%s";
- if (at) {
- brace = index(at+1, '>');
- if (brace) *brace = '\0';
- official = get_official(at+1, (int *)NULL);
- if (official) {
- *at = '\0';
- fmt = brace ? "%s@%s>" : "%s@%s";
- }
- else if (brace)
- *brace = '>';
- }
- fprintf(rm_msgf, fmt, p , official);
-
- if (debug) {
- printf("arpa munge gives ");
- printf(fmt, p, official);
- printf("\n");
- }
-
- free(p);
- }
- free(frees);
- }
-
-
-
- /*
- * datecvt() -- convert UNIX ctime() style date to ARPA style
- * (change done in place)
- */
- datecvt (date, newdate)
- char *date;
- char *newdate;
- {
- /*
- * LMCL: Changed the default timezone, when none given, to be GMT
- * 012345678901234567890123456789
- * Wed Nov 18 22:23:17 1981 Unix
- * Wed, 18 Nov 81 22:23:45 GMT ARPA
- * or
- * Wed Nov 18 22:23:17 EDT 1981 Unix
- * Wed, 18 Nov 81 22:23:45 EDT ARPA
- * or even (LMCL yet again)
- * Mon Apr 23 16:50 BST 1984 Unix
- */
-
- if (isdigit(date[0]) || date[3] == ',' || isdigit(date[5]))
- (void) strcpy(newdate, date); /* Probably already ARPA */
- else if (isdigit(date[20]))
- (void) sprintf(newdate, "%.3s, %.2s %.3s %.2s %.2s:%.2s:%.2s GMT",
- date, date+8, date+4, date+22, date+11, date+14, date+17);
- else if (isalpha(date[17])) /* LMCL. Bum Unix format */
- (void) sprintf(newdate, "%.3s, %.2s %.3s %.2s %.2s:%.2s:00 GMT",
- date, date+8, date+4, date+23, date+11, date+14);
- else
- (void) sprintf(newdate, "%.3s, %.2s %.3s %.2s %.2s:%.2s:%.2s %.3s",
- date, date+8, date+4, date+26,
- date+11, date+14, date+17, date+20);
- }
-
- /**/
- msg_stash (dest, rep)
- char *dest;
- struct rp_bufstruct *rep;
- {
- Err_stash *es;
-
- /*
- * I wanted to do this using a linked list
- * but there was something peculiar in the
- * Orion which meant that the code failed
- */
- if (e_s_count >= MAXERRSTASH) {
- e_s_other++;
- return;
- }
- es = &e_stash[e_s_count++];
- (void) strcpy(es->e_s_dest, dest);
- es->e_s_reason = *rep;
- }
-
- msg_return()
- {
- Err_stash *ep;
- int emax;
- #ifdef CITATION
- int lines;
- #endif
-
- ml_init(YES, NO, "UUCP (rmail)", "Failed Message");
- ml_adr(rm_from);
- ml_aend();
- ml_tinit();
- ml_txt("Your message was not delivered to:\n ");
- for (ep = e_stash; ;) {
- ml_txt(ep->e_s_dest);
- ml_txt("\nFor the following reason:\n ");
- to80(ep->e_s_reason.rp_line);
- ml_txt(ep->e_s_reason.rp_line);
- if (++ep < &e_stash[e_s_count])
- ml_txt("\n\nIt was also not delivered to:\n ");
- else
- break;
- }
- if (e_s_other)
- ml_txt("\nThere were other addressing errors\n\n");
- e_s_other = 0;
- emax = e_s_count; /* for non delivery */
- e_s_count = 0;
- #ifdef CITATION
- ml_txt("\n\nYour message begins:\n\n");
- rewind(rm_msgf);
- while (fgets(linebuf, sizeof linebuf, rm_msgf) != NULL) {
- ml_txt(linebuf);
- if (linebuf[0] == '\n')
- break;
- }
- if (!feof(rm_msgf)) {
- lines = 0;
- for (lines = CITATION; --lines > 0 &&
- fgets(linebuf, sizeof linebuf, rm_msgf) != NULL;) {
-
- if (linebuf[0] == '\n')
- lines++; /* truly blank lines don't count */
- ml_txt(linebuf);
- }
- if (!feof(rm_msgf)) /* if more, give an elipses */
- ml_txt("...\n");
- }
- #else
- ml_txt("\n\n--------------- Returned Mail ---------------\n\n");
- rewind(rm_msgf);
- ml_file(rm_msgf);
- ml_txt("--------------- End of Returned Mail -------------\n");
- #endif
- if (ml_end(OK) != OK) {
-
- ml_init(YES, NO, "UUCP (rmail)", "Failed Err Message");
- ml_adr(supportaddr);
- ml_aend();
- ml_tinit();
- ml_txt("Error message failed to:\n ");
- ml_txt(rm_from);
- ml_txt("\n\nWhen failing to send to:\n ");
- for (ep = e_stash; ;) {
- ml_txt(ep->e_s_dest);
- ml_txt("\nFor the following reason:\n ");
- ml_txt(ep->e_s_reason.rp_line);
- if (++ep < &e_stash[emax])
- ml_txt("\nand failing to send to:\n ");
- else
- break;
- }
- ml_txt("\n\n----------- Returned Mail --------------\n\n");
- rewind(rm_msgf);
- ml_file(rm_msgf);
- ml_txt("-------- End of Returned Mail ---------------\n");
- if (ml_end(OK) != OK)
- bomb("Failed to returnerror message to overseer");
- }
- }
-
- /*
- * line formatter stolen from niftp/rtn_proc.c
- */
- to80(from)
- char *from;
- {
- register char *p;
- char *lastspace = NULL, *lastnl = from;
-
- for (p = from ; *p ; p++) {
- if (*p != ' ' && *p != '\t')
- continue;
- if (p - lastnl > 80) {
- if (lastspace != NULL) {
- *lastspace = '\n';
- lastnl = lastspace;
- if (p - lastnl <= 80) {
- lastspace = p;
- continue;
- }
- }
- lastspace = NULL;
- *p = '\n';
- lastnl = p;
- continue;
- }
- lastspace = p;
- }
- if (p - lastnl > 80 && lastspace != NULL)
- *lastspace = '\n';
- }
-
- /* */
-
- xsubmit(from, argv, argc)
- char *from;
- char **argv;
- int argc;
- {
- register char *p, *q;
- struct rp_bufstruct thereply;
- char buf[LINESIZE];
- char subargs[LINESIZE];
- char *un_bang();
- int len;
-
- rewind (rm_msgf);
-
- if (debug) {
- for (argv++; --argc > 0; argv++)
- printf("arg = %s\n", un_bang(*argv));
- while (fgets(buf, LINESIZE-1, rm_msgf) != NULL)
- printf("T=%s", buf);
- if (ferror(rm_msgf))
- bomb("Error reading message file");
-
- exit(0);
- }
-
- if (rp_isbad (mm_init()) || rp_isbad (mm_sbinit ()))
- bomb("Failed to initialise submit");
-
- /* Set nameserver timeout up high -- DSH */
- (void) sprintf(subargs, "lvmti%s*hk30h", uchan);
-
- if (nextdoor[0]) {
- q = subargs + strlen(subargs);
- for (p = nextdoor; *p;) {
- if (!isprint(*p)) {
- p++;
- continue;
- }
- if (*p == '\'') *q++ = '\\';
- *q++ = *p++;
- }
- *q = '\0';
- }
- (void) strcat(subargs, "*");
-
- if (rp_isbad(mm_winit((char *)NULL, subargs, from)))
- bomb("mm_winit(%s, %s) failed", subargs, from);
- if (rp_isbad(mm_rrply(&thereply, &len)))
- bomb("Failed to read address reply");
- if (rp_isbad(thereply.rp_val))
- bomb("Initialization failure '%s'", thereply.rp_line);
-
- for (argv++; --argc > 0; argv++) {
- char *name;
-
- name = un_bang(*argv);
- if (rp_isbad(mm_wadr("", name)))
- bomb("failed to write address '%s'", name);
-
- if (rp_isbad(mm_rrply(&thereply, &len)))
- bomb("Failed to read address reply");
-
- switch (rp_gval(thereply.rp_val)) {
- case RP_DOK:
- case RP_AOK:
- break;
-
- case RP_USER:
- msg_stash(name, &thereply);
- break; /* LMCL: Was return*/
-
- default:
- bomb("Address check failure '%s' (%s)",
- thereply.rp_line,
- rp_valstr(thereply.rp_val));
- }
- }
-
- if (rp_isbad(mm_waend()))
- bomb("Failed to write address end");
- rewind(rm_msgf);
- while (fgets(buf, LINESIZE-1, rm_msgf) != NULL)
- if (rp_isbad(mm_wtxt(buf, strlen(buf))))
- bomb("mm_wtxtfailure");
- if (ferror(rm_msgf))
- bomb("Error reading messge file");
-
- if (rp_isbad(mm_wtend()))
- bomb("mm_wtend error");
-
- if (rp_isbad(mm_rrply(&thereply, &len)))
- bomb("mm_rrply at end of message");
-
- if (rp_isbad(thereply.rp_val))
- bomb("Bad text reply val '%s' (%s)", thereply.rp_line,
- rp_valstr(thereply.rp_val));
-
- mm_sbend();
- if (e_s_count)
- msg_return();
- return;
- }
-
- /*VARARGS1*/
- bomb(fmt, a, b, c)
- char *fmt, *a, *b, *c;
- {
- if (e_s_count)
- msg_return();
- ll_log(logptr, LLOGFAT, fmt, a, b, c);
- ll_close(logptr);
- fputs("rmail: ", stderr);
- fprintf(stderr, fmt, a, b, c);
- putc('\n', stderr);
- exit(99);
- }
-
- /*
- * fromcvt() -- trys to convert the UUCP style path into an ARPA style name.
- */
- fromcvt(from, newfrom)
- char *from, *newfrom;
- {
- register char *cp;
- register char *sp;
- register char *off;
- char *at, *atoff;
- char atstore[LINESIZE], buf[LINESIZE];
- char *get_official();
- int saveit;
-
- if (debug)
- printf("fromcvt on %s\n", from);
-
- (void) strcpy(buf, from);
- cp = rindex(buf, '!');
- if (cp == 0) {
- (void) strcpy(newfrom, from);
- return;
- }
- /*
- * look for @site at the end of the name
- */
- atoff = NULL;
- if ((at = index(cp, '@')) != NULL) {
- /* got one - is it followed by a ! ? */
- if (index(at+1, '!') != NULL)
- at = NULL;
- else {
- /* look up the official name of the at site */
- atoff = get_official(at+1, &saveit);
- if (atoff) {
- if (saveit) {
- (void) strcpy(atstore, atoff);
- atoff = atstore;
- }
- }
- }
- }
- *cp = 0;
- while (sp = rindex(buf, '!')) {
- /*
- * scan the path backwards looking for hosts that we
- * know about
- */
- if (off = get_official(sp+1, &saveit)) {
- if (atoff && lexequ(atoff, off))
- (void) strcpy(newfrom, cp+1);
- else
- (void) sprintf(newfrom, "%s@%s", cp+1, off);
- return;
- }
- else if (at && lexequ(at+1, sp+1)) {
- (void) strcpy(newfrom, cp+1);
- return;
- }
- *cp = '!';
- cp = sp;
- *cp = 0;
- }
- if (off = get_official(buf, (int *)NULL))
- (void) sprintf(newfrom, "%s@%s", cp+1, off);
- else
- (void) sprintf(newfrom, "%s@%s", cp+1, buf);
- }
-
- /*
- * This piece added by Peter Collinson (UKC)
- * rather than just making rmail submit into the uucp channel which
- * is hard coded. First look up in a table 'rmail.chans' for entries
- * of the form
- * nextdoor:channel
- * If the name exists then use that channel otherwise just default to
- * the uucp channel. This is for authorisation purposes really
- */
- set_channel(nxt)
- char *nxt;
- {
- Table *tb_rmchans;
- char tuchan[LINESIZE];
-
- #ifdef DEBUG
- ll_log(logptr, LLOGBTR, "set_channel(%s)", nxt);
- #endif
- /*
- * set default
- */
- (void) strcpy(uchan, Uchan);
-
- if ((tb_rmchans = tb_nm2struct("rmail.chans")) != (Table *)NOTOK) {
- /*
- * Well, we have the table. Extract name of current channel
- * from list of channels
- */
- if (tb_k2val(tb_rmchans, TRUE, nxt, tuchan) == OK)
- (void) strcpy(uchan, tuchan);
- }
-
- /*
- * Get the channel attributes
- */
- if ((chanptr = ch_nm2struct(uchan)) == (Chan *)NOTOK) {
- /* fail safe - not sure that we should do this */
- /* find the default channel */
- if ((chanptr = ch_nm2struct(Uchan)) == (Chan *)NOTOK)
- bomb("Cannot look up channel '%s'\n", uchan);
- }
- }
-
- /*
- * Check if the from machine which we have constructed actually
- * contains two references to the same machine of the form
- * site.uucp!site.??.uk!something
- * if so replace by the single official name
- *
- * This can fail can't it? -- DSH
- */
- domain_cross(route)
- char *route;
- {
- char *enda, *endsecond, *official, *second;
- char *host_equal();
-
- second = index(route, '!');
- if (second == (char *)NULL)
- return;
- second++;
- endsecond = index(second, '!');
- if (endsecond == (char *)NULL)
- return;
- second[-1] = '\0';
- *endsecond = '\0';
- if (official = host_equal(route, second)) {
- enda = strdup(endsecond+1);
- (void) strcpy(route, official);
- (void) strcat(route, "!");
- (void) strcat(route, enda);
- free(enda);
- }
- else {
- second[-1] = '!';
- *endsecond = '!';
- }
- }
-
- /*
- * host_equal
- * a routine to see whether the strings which are input
- * are in fact the same host
- * Returns the official name if they are and a null pointer if not
- */
- char *
- host_equal(n1, n2)
- char *n1, *n2;
- {
- static char res1[LINESIZE];
- char *o1, *o2;
- char *get_official();
- int saveit;
-
- o1 = get_official(n1, &saveit);
- if (o1 == NULL)
- return(NULL);
- if (saveit) {
- (void) strcpy(res1, o1);
- o1 = res1;
- }
- o2 = get_official(n2, &saveit);
- if (o2 == NULL)
- return(NULL);
- if (lexequ(o1, o2) == TRUE)
- return(o1);
- return(NULL);
- }
-
- /* */
-
- /*
- * These routines perform some caching on the host name/official
- * name pair in and attempt to reduce overheads
- */
- Official *off_cache; /* pointer to the base of the cache */
- #define OFFICIALSIZE 50 /* Chunk size for the cache */
- int off_size; /* current size of the cache */
- int off_used; /* current set which are used */
- /*
- * get a host from the domain tables
- * if the cache has fallen over due to lack of memory
- * then the saveit switch will be set showing that the
- * address is in static memory
- */
- char *
- get_official(host, saveit)
- char *host;
- int *saveit; /* set if the cache is not working */
- {
- register Official *off;
- static char res[LINESIZE];
- Domain *dmn;
- Domain *dm_v2route();
- Dmn_route rbuf, *route = &rbuf;
- int sadummy;
-
- if (debug)
- printf("get_official called for %s\n", host);
-
- if (saveit == (int *)NULL)
- saveit = &sadummy;
- *saveit = 0; /* assume cache is working */
-
- if (off_size == 0) {
- off_cache = (Official *)malloc(OFFICIALSIZE*sizeof(Official));
- off_size = OFFICIALSIZE;
- if (debug)
- printf("Cache%sset - %d items\n",
- off_cache ? " " : " not " ,
- off_cache ? off_size : 0);
- }
-
- /*
- * If we have managed to get space for the cache
- * search it for the name
- */
- if (off_cache == (Official *)NULL)
- *saveit = 1;
- else {
- for (off = off_cache; off < &off_cache[off_used]; off++)
- if (*host == *off->o_host && lexequ(host, off->o_host)) {
- if (debug)
- printf("Cache hit - %s\n", off->o_official);
- return(off->o_official);
- }
- }
-
- /*
- * Bad news - we must do something to get the information
- */
- dmn = dm_v2route(host, res, route);
- if (dmn == (Domain *)NOTOK) {
- if (debug)
- printf("%s not in tables\n", host);
- return(NULL);
- }
-
- /*
- * we have a hit in the tables
- * save it in the cache
- */
- if (off_used >= off_size) {
- off_size += OFFICIALSIZE;
- /*NOSTRICT*/
- off_cache = (Official *)realloc(off_cache,off_size * sizeof(Official));
- if (debug) {
- if (off_cache)
- printf("Cache grown to %d items\n", off_size);
- else
- printf("Cache grow failed\n");
- }
- }
-
- if (off_cache) {
- off = &off_cache[off_used];
- if ((off->o_host = strdup(host)) &&
- (off->o_official = strdup(res))) {
- off_used++;
- if (debug) {
- printf("%s - %s stored in cache - cachesize %d\n",
- off->o_host,
- off->o_official,
- off_used);
- }
- return(off->o_official);
- }
- }
-
- *saveit = 1;
- if (debug)
- printf("%s - %s not cached\n", host, res);
- return(res);
- }
-
- /*
- * Added Peter Collinson June 1987
- * take a possibly pure bang address and convert it into
- * 733 % @ format
- *
- *
- * The above is unnecessary and triggers problems, such as
- * propagation of
- * rmail oddjob!ncar!mailrus!utai!watmath!looking!brad
- * as
- * rmail ncar!brad%looking%watmath%utai%mailrus
- *
- * Instead of converting x!y!z!user to user%z%y@x, convert
- * it into y!z!user@x. This is perfectly fine for systems
- * that obey RFC-976 (which MMDF is one of).
- * -- JG
- */
- char *
- un_bang(adr)
- register char *adr;
- {
- register char *bangptr, *dest;
-
- /*
- * get out of anything other than bangs
- */
- if (index(adr, '@') || index(adr, '%') || index(adr, ':'))
- return(adr);
- /*
- * get out if no '!'
- */
- if ((bangptr = index(adr, '!')) == (char *)NULL)
- return(adr);
-
- /*
- * convert "a!b!c!user" into "b!c!user@a"
- */
- dest = malloc(strlen(adr+16));
- (void) strcpy(dest, bangptr+1);
- (void) strcat(dest, "@");
- *bangptr = '\0';
- (void) strcat(dest, adr);
- (void) strcpy(adr, dest);
- free(dest);
- return(adr);
- }
-